Sublevels
~~~~~~~~~
There are two kinds of runlevels in sninit: primary runlevels 0, 1, 2, ... 9,
and sublevels a, b, c, d, e, f. Sublevels extend the notion of ondemand
runlevels from sysvinit.

Sublevels go in the runlevels field in inittab together with the primary
runlevels. Here's how they affect when an initrec will be started:

	123	runlevels 1, 2 or 3, regardless of sublevels
	12a	runlevels 1 or 2, but only if sublevel a is active
	12ab	runlevels 1 or 2, if at least one of sublevels a, b is active
	(empty)	all runlevels except 0
	ab	all runlevels except 0 if either a or b is active

Primary runlevels are mutually exclusive; sninit can only be in one of them.
Sublevels aren't exclusive, and any set of sublevels can be active at any
given time. To control currently active sublevels, use + and - commands
in telinit:

	telinit +a

activates sublevel a,

	telinit -bc

deactivates sublevels b and c.


Sysvinit compatibility
~~~~~~~~~~~~~~~~~~~~~~
When used without specifying primary runlevels, sublevels act just like
ondemand runlevels in sysvinit. Specifically,
	
	name:a:ondemand:command

in sysvinit translates into
	
	name:a::command

in sninit. Telinit commands are somewhat different, in sninit it's always "+a"
instead of just "a" to activate sublevel a.


Init state and switching sublevels
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The actual runlevels sninit switches between are combinations of one primary
runlevel and some (possibly empty) set of sublevels.
The complete runlevel after

	telinit 4
	telinit +ac

will be "4ac", that is, primary level 4 with sublevels a and c activated.
Activating sublevel b in this situation with
	
	telinit +b

would result in sninit switching from runlevel "4ac" to to runlevel "4abc",
running r-type entries if necessary just like when switching primary runlevels.

Currently switching primary runlevel results in the change of the primary
runlevel only, i.e. in the above situation running

	telinit 5

will move sninit to runlevel "5abc", not just "5". To drop any sublevels
when switching,

	telinit 5-

instead.


Rationale
~~~~~~~~~
While relatively easy to implement, ondemand runlevels are not among sysvinit's
most used features. Actually, their role in sysvinit is similar to the role
of initrec names in sninit: starting/stopping processes on the fly with
telinit. There are only three of them, so they are not terribly useful,
but the idea is the same anyway.

In sninit, the main reason for implementing sublevels was handling independent
aspects of system state, like network connectivity status (online/offline),
being/not being an access point, and possibly laptop power modes.

Stuff like this works a lot like runlevels, in that there are some script to run
when switching to battery power, there are some scripts to run when going back
to mains, some daemons to run only when providing AP services and such.

Sublevels provide a reasonably clean and readable way to handle this situation.
Having battery/mains mode as a sublevel means primary runlevels can be used
solely for managing running daemons.


Negating sublevels
~~~~~~~~~~~~~~~~~~
The problem: how should X23a entry work?

Without sublevels, the solution is relatively straightforward: X23 is the same
as R0--1456789, and it works as expected: X23 entry is run when leaving
runlevels 2 or 3.
Which is the exactly opposite of R23 which is run on entering said runlevels.

The same trick does not work with sublevels, because inverting sublevels
makes no sense. So instead, there are two approaches:

	* primary inversion
	  keep inverting primary runlevels only which leaving sublevels unchanged

	* complete inversion
	  do not invert the masks, keep a dedicated C_INVERT flag and
	  invert shouldberunning() return instead

While primary inversion looks cleaner and easier to implement,
it results in some really weird behavior. Not really incorrect, just weird;
something I don't think will be of much use. So the decision was made to go
with the complete inversion instead.

The following examples show two entries p1 and p2 with the same mask,
one inverted and one not:

    Primary inversion

    R2  -> R2a     run p1                            0123456789 abcdef
    R2a -> R2      nothing                p1   R2a   --x------- x-----
    R2a -> R3a     run p2                 p2   X2a   xx-xxxxxxx x-----
    R2a -> R3      nothing

    Complete inversion

    R2  -> R2a     run p1                          I 0123456789 abcdef
    R2a -> R2      run p2                 p1   R2a   --x------- x-----
    R2a -> R3a     run p2                 p2   X2a * --x------- x-----
    R2a -> R3      run p2

Primary inversion works by "hiding" entries which do not match current
sublevel mask. With complete inversion, R2a acts as a separate runlevel,
keeping all runlevel semantics, so R2 <-> R2a, R2a <-> R3a and R2a <-> R3
all work as regular runlevel changes.

The downside of complete inversion is that it keeps a dedicated INVERT flag
(but that is handled in shouldberunning() anyway) and needs some additional
logic for "enable entry" command (not really a problem).
